#!/bin/bash

#程序配置
logpath="/home/CaptureLogs"    #日志保存路径
remotepath="//192.168.6.6/AutoBackup"    #远程共享路径，这里用的是cifs共享路径，也可以换成nfs共享路径
capturepath="/mnt/data_192_168_6_6"    #mount远程共享路径并捕获快照的路径
storepath="/WD-HDD/snapshots"    #快照存储路径
preservenumbs=189    #快照保存数目，不论快照保存天数设置是多少，至少保存多少个快照
preservedays=189    #快照保存天数，不论快照保存数目设置是多少，至少保存多少天快照

if [ ! -d $capturepath ];then mkdir -p $capturepath; if [ $? -ne 0 ]; then exit; fi; fi
if [ ! -d $storepath ];then mkdir -p $storepath; if [ $? -ne 0 ]; then exit; fi; fi
if [ ! -d $logpath ];then mkdir -p $logpath; if [ $? -ne 0 ]; then exit; fi; fi

#挂载需要捕获快照的源目录
starttime=`date +%Y%m%d_%H%M%S`
n=0
while :
do
    mountpoint -q $capturepath    #目录是否为挂载点
    if [ $? -eq 0 ]; then
        ls $capturepath    #目录是否可正常访问
        if [ $? -eq 0 ]; then
            break
        else
            umount -f $capturepath
        fi
    fi
    mount -t cifs -o username="user",password="abcd12345678" $remotepath $capturepath 2> /dev/null    #挂载远程目录，这里是cifs共享，也可换成nfs共享
    n=`expr $n + 1`
    if [ $n -eq 30 ]; then
        echo $starttime "Connect share folder false" >> $logpath"/error_"$starttime.txt
        exit
    fi
    sleep 10s
done

#备份IFS并设置IFS为$'\n'以使shell顺利处理含空格的路径和文件名
ifsold=$IFS
IFS=$'\n'

#获取需要捕获快照的目录下所有文件 和空文件夹
capfiles=(`find $capturepath -type f 2> /dev/null`)
cd $capturepath
capmptdirs=(`find -type d -empty | sed "s/\.\///" 2> /dev/null`)

#获取需要参照的上一个快照
lastsnapath=$(find $storepath -maxdepth 1 -type d -exec basename {} \; | sed -n "/^[1-2][0-9][0-9][0-9][0-1][0-9][0-3][0-9][_][0-2][0-9][0-5][0-9][0-5][0-9]$/p" | sort -n | sed -n '$p' 2> /dev/null)

#开始捕获快照
lnfiles=()
cpfiles=()
for cfile in ${capfiles[*]}
do
    if [ $lastsnapath ]; then
        dfile=$storepath"/"$lastsnapath${cfile#$capturepath}
        if [ -f $dfile ]; then    #如果上一个快照中存在和要复制的同名的文件，则比对它们是否一致
            sstat=($(stat --format "%Y"$'\n'"%s" $cfile 2> /dev/null))    #源文件修改时间的时间戳和文件大小
            dstat=($(stat --format "%Y"$'\n'"%s" $dfile 2> /dev/null))    #已存在文件的修改时间的时间戳和文件大小
            if [ ${sstat[0]} -eq ${dstat[0]} -a ${sstat[1]} -eq ${dstat[1]} ]; then
                lnfiles+=(${cfile#$capturepath"/"})    #文件名、修改时间和文件大小均相等的文件将创建硬链接
                continue
            fi
        fi
    fi
    cpfiles+=(${cfile#$capturepath"/"})    #否则将进行复制
done
newsnapshot=$(date +%Y%m%d_%H%M%S)    #将要创建的新快照名称，快照名称为 年月日_时分秒
mkdir -p $storepath"/"$newsnapshot
echo $newsnapshot "Start Capture Files..." > $logpath"/log_"$newsnapshot.txt
if [ $lnfiles ]; then
    cd $storepath"/"$lastsnapath
    echo "----------------Link files----------------" >> $logpath"/log_"$newsnapshot.txt
    \cp -lv --parents ${lnfiles[*]} $storepath"/"$newsnapshot &>> $logpath"/log_"$newsnapshot.txt
    lns=$?
else
    lns=0
fi
cpfiles+=(${capmptdirs[*]})    #追加要复制的空文件夹
if [ $cpfiles ]; then
    cd $capturepath
    echo "----------------Copy files----------------" >> $logpath"/log_"$newsnapshot.txt
    \cp -pauv --parents --backup=numbered ${cpfiles[*]} $storepath"/"$newsnapshot &>> $logpath"/log_"$newsnapshot.txt
    cps=$?
else
    cps=0
fi
donetime=`date +%Y%m%d-%H%M%S`
echo $donetime "Capture Files Done!" >> $logpath"/log_"$newsnapshot.txt
if [ $lns -ne 0 -o $cps -ne 0 ];then    #如果捕获快照的过程中有出错，则删除这个快照
    rm -rf $storepath"/"$newsnapshot
    echo $newsnapshot" Capture false" > $logpath"/caperror_"$newsnapshot.txt
fi

#删除过期快照 和日志
snapshots=($(find $storepath -maxdepth 1 -type d -exec basename {} \; | sed -n "/^[1-2][0-9][0-9][0-9][0-1][0-9][0-3][0-9][_][0-2][0-9][0-5][0-9][0-5][0-9]$/p" | sort -n 2> /dev/null))    #获取所有快照并按时间排序
delnumb=$(expr ${#snapshots[*]} - $preservenumbs)    #比“快照保存数目”多出的快照数量
expiredate=$(date -d -${preservedays}day +%Y%m%d)    #过期日期
if [ $delnumb -gt 0 ]; then
    IFS=$' \t\n'
    expiresnaps=(${snapshots[*]:0:$delnumb})    #取出将要删除的快照名称
    IFS=$'\n'
    for del in ${expiresnaps[*]}
    do
        snapdate=${del:0:8}
        if [ $(expr $expiredate - $snapdate) -gt 0 ]; then    #快照是否到了过期日期
            rm -rf $storepath"/"$del
            rm -rf $logpath"/*_"${del}.txt
        fi
    done
fi

#恢复IFS设置
IFS=$ifsold
